#ifndef _CLIENT_HPP_
#define	_CLIENT_HPP_

/*******************************************************************************
 ** Name: Client.hpp                                                          **
 ** Description:                                                              **
 **                                                                           **
 ** Open Source Initiative (OSI) Approved License                             **
 **                                                                           **
 **  Copyright (c) 2009-2010 Barry "Gian" James  <bjames@munixos.net>         **
 **  All rights reserved.                                                     **
 **                                                                           **
 **  Redistribution and use in source and binary forms, with or without       **
 **  modification, are permitted provided that the following conditions are   **
 **  met:                                                                     **
 **                                                                           **
 **  * Redistributions of source code must retain the above copyright notice, **
 **    this list of conditions and the following disclaimer.                  **
 **  * Redistributions in binary form must reproduce the above copyright      **
 **    notice, this list of conditions and the following disclaimer in the    **
 **    documentation and/or other materials provided with the distribution.   **
 **                                                                           **
 **  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS      **
 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED **
 ** TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A           **
 ** PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT        **
 ** HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,    **
 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED  **
 ** TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR    **
 ** PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF    **
 ** LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING      **
 ** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS        **
 ** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.              **
 **                                                                           **
 ******************************************************************************/
// Created on March 24, 2010, 12:07 AM
// Modified $Date: 2011-09-18 21:48:59 +0000 (Sun, 18 Sep 2011) $ by $Author: gian.james $

#define Client_hpp_ID   "$Id: client.hpp 145 2011-09-18 21:48:59Z gian.james $"

#include <string>
extern "C" {
#include <time.h>
}
#include "Socket.hpp"
#include "ringbuff.hpp"
#include "character.hpp"
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/ordered_index.hpp>
using boost::multi_index_container;
using namespace boost::multi_index;

#define MAX_RECV_LEN	256

// Disconnection codes
#define DISCO_LOGOUT	1	// normal logout/disconnection
#define DISCO_IDLE		2	// disconnected for being idle
#define DISCO_KILLED	3	// forceably removed with @kill
#define DISCO_REBOOT	4	// system going down for reboot
#define DISCO_BADLOGIN	5	// too many failed login attempts
#define DISCO_CLOSED	6	// no new or otherwise users allowed in
#define DISCO_FULL		7	// too many players logged in

#define CLIENT_MXP_ENA		0x0001
#define CLIENT_QUOTA_ENA	0x0002
#define CLIENT_I3_ENA		0x0004
#define CLIENT_IPV6_ENA		0x0008
#define CLIENT_COLOR_ENA	0x0010
#define CLIENT_COMPRESSION_ENA 0x0020
#define CLIENT_SUSPECT		0x0040

// Only derives from WorldObject for efficient command workage
class Client : public WorldObject {
public:
    Client(int s);
    Client(const std::string & n);
    Client(const Client& orig);
    ~Client();

    int     Sock() { return sock; }
    void	Sock(int s) { sock = s; }
    std::string & UserName() { return sname; }
    void    SetUserName(std::string & n) { sname = n; }
    void    SetRecvTime(time_t l) { lastRecv = l; }
    time_t  RecvTime() { return lastRecv; }
    uint16_t &	Flags() { return flags; }
    sockaddr_in & SocketAddress() { return saddr; }
    void	SocketAddress(sockaddr_in & s);
	short	SocketFamily() { return saddr.sin_family; }
	Dossier * Player() { return player; }

    int		IsMXPEnabled() { return (flags & CLIENT_MXP_ENA); }
    int		IsQuotaEnabled() { return (flags & CLIENT_QUOTA_ENA); }
    int		IsI3Enabled() { return (flags & CLIENT_I3_ENA); }
    int		IsIPv6Enabled() { return (flags & CLIENT_IPV6_ENA); }
    int		IsCompressionEnabled() { return (flags & CLIENT_COMPRESSION_ENA); }
    int		IsThemeable() { return (flags & CLIENT_COLOR_ENA); }

    // These commands have already been ACL'd for the message to
    // have reached us at our client.
    // This goes to this client/player from 'from'
    int		Tell(std::string from, char * msg, ...);
    // This is a public say from 'from'
    int		Say(std::string from, char * msg, ...);
    // This is a global shout from 'from'
    int		Shout(std::string from, char * msg, ...);
    // A broadcast message to all users from 'from'
    int		Wall(std::string from, char * msg, ...);
    // A broadcast message to all ops from 'from'
    int		Wallop(std::string from, char * msg, ...);
    // Other actionable items are forwarded to Dossier->Character
    // This is used by the system to give feedback from commands
    int		System(std::string from, char * msg, ...);

//private:
    // public for multi_index_container support blech;
    int     sock;       //!< socket file descriptor
    std::string sname;  //!< character name/key for client map
private:
    time_t  loginTime;
    time_t  lastRecv;	// time since we got a msg from this client
    time_t	logoutTime;
    // TODO maybe a pointer to their Dossier or Character should go in here
    Dossier * player;
    int		quota;		// TODO maybe implement, maybe not
    uint16_t flags;
    sockaddr_in	saddr;

    std::ringbuffer<std::string> *	ibuff;
    std::ringbuffer<std::string> *	obuff;
};

struct sock { };
struct sname { };
typedef multi_index_container<
	Client*,
	indexed_by<
		ordered_unique<tag<sock>, BOOST_MULTI_INDEX_MEMBER(Client,int,sock)>,
		ordered_unique<tag<sname>, BOOST_MULTI_INDEX_MEMBER(Client,std::string,sname)>
	>
> clientSet;
typedef clientSet::index<sock>::type clientSetBySocket;
typedef clientSet::index<sname>::type clientSetByName;

Client *	FindClient(int);
Client *	FindClient(std::string &);

extern clientSet clients;

#endif	/* _CLIENT_HPP_ */

